﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Nirvana
{
    [Serializable]
    public sealed class UIVariable 
    {
        [SerializeField]
        private string variableName;
        [SerializeField]
        private UIVariableType variableType;
        [SerializeField]
        private bool boolValue;
        [SerializeField]
        private long intValue;
        [SerializeField]
        private float floatValue;
        [SerializeField]
        private string stringValue;
        [SerializeField]
        private AssetID assetValue;
        private Action onValueChanged, onValueInitialized;
        [HideInInspector]
        public List<UIVariableBind> UIVariableBindList = new List<UIVariableBind>();
        

        public string VariableName { get { return variableName; } }
        public UIVariableType VariableType { get { return variableType; } }
        public bool GetBoolean() { return this.boolValue; }
        public int GetInteger() { return (int)this.intValue; }
        public float GetFloat() { return this.floatValue; }
        public string GetString() { return this.stringValue; }
        public AssetID GetAsset() { return this.assetValue; }
        public object ValueObject
        {
            get
            {
                switch (this.variableType)
                {
                    case UIVariableType.Boolean: return this.boolValue;
                    case UIVariableType.Integer: return this.intValue;
                    case UIVariableType.Float: return this.floatValue;
                    case UIVariableType.String: return this.stringValue;
                    case UIVariableType.Asset: return this.assetValue;
                    default: return null;
                }
            }
        }



        public void Init()
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    {
                        this.intValue = 0L;
                        this.floatValue = 0f;
                        this.stringValue = null;
                        this.assetValue = default(AssetID);
                        break;
                    }
                case UIVariableType.Integer:
                    {
                        this.boolValue = false;
                        this.floatValue = 0f;
                        this.stringValue = null;
                        this.assetValue = default(AssetID);
                        break;
                    }
                case UIVariableType.Float:
                    {
                        this.boolValue = false;
                        this.intValue = 0L;
                        this.stringValue = null;
                        this.assetValue = default(AssetID);
                        break;
                    }
                case UIVariableType.String:
                    {
                        this.boolValue = false;
                        this.intValue = 0L;
                        this.floatValue = 0f;
                        this.assetValue = default(AssetID);
                        break;
                    }
                case UIVariableType.Asset:
                    {
                        this.boolValue = false;
                        this.intValue = 0L;
                        this.floatValue = 0f;
                        this.stringValue = null;
                        break;
                    }
            }
        }
        public void InitValue(bool value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.InitBoolean(value);
                    break;
                case UIVariableType.Integer:
                    this.InitInteger((!value) ? 0L : 1L);
                    break;
                case UIVariableType.Float:
                    this.InitFloat((!value) ? 0f : 1f);
                    break;
                case UIVariableType.String:
                    this.InitString(value.ToString());
                    break;
            }
        }
        public void InitValue(long value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.InitBoolean(value != 0L);
                    break;
                case UIVariableType.Integer:
                    this.InitInteger(value);
                    break;
                case UIVariableType.Float:
                    this.InitFloat((float)value);
                    break;
                case UIVariableType.String:
                    this.InitString(value.ToString());
                    break;
            }
        }

        public void InitValue(float value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.InitBoolean(!Mathf.Approximately(value, 0f));
                    break;
                case UIVariableType.Integer:
                    this.InitInteger((long)value);
                    break;
                case UIVariableType.Float:
                    this.InitFloat(value);
                    break;
                case UIVariableType.String:
                    this.InitString(value.ToString());
                    break;
            }
        }
        public void InitValue(string value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.InitBoolean(bool.Parse(value));
                    break;
                case UIVariableType.Integer:
                    this.InitInteger(long.Parse(value));
                    break;
                case UIVariableType.Float:
                    this.InitFloat(float.Parse(value));
                    break;
                case UIVariableType.String:
                    this.InitString(value);
                    break;
            }
        }
        public void SetValue(bool value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.SetBoolean(value);
                    break;
                case UIVariableType.Integer:
                    this.SetInteger((!value) ? 0L : 1L);
                    break;
                case UIVariableType.Float:
                    this.SetFloat((!value) ? 0f : 1f);
                    break;
                case UIVariableType.String:
                    this.SetString(value.ToString());
                    break;
            }
        }
        public void SetValue(long value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.SetBoolean(value != 0L);
                    break;
                case UIVariableType.Integer:
                    this.SetInteger(value);
                    break;
                case UIVariableType.Float:
                    this.SetFloat((float)value);
                    break;
                case UIVariableType.String:
                    this.SetString(value.ToString());
                    break;
            }
        }

        public void SetValue(float value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.SetBoolean(!Mathf.Approximately(value, 0f));
                    break;
                case UIVariableType.Integer:
                    this.SetInteger((long)value);
                    break;
                case UIVariableType.Float:
                    this.SetFloat(value);
                    break;
                case UIVariableType.String:
                    this.SetString(value.ToString());
                    break;
            }
        }

        public void SetValue(string value)
        {
            switch (this.variableType)
            {
                case UIVariableType.Boolean:
                    this.SetBoolean(bool.Parse(value));
                    break;
                case UIVariableType.Integer:
                    this.SetInteger(long.Parse(value));
                    break;
                case UIVariableType.Float:
                    this.SetFloat(float.Parse(value));
                    break;
                case UIVariableType.String:
                    this.SetString(value);
                    break;
            }
        }
        public void SetAsset(string bundle, string asset)
        {
            this.SetAsset(new AssetID(bundle, asset));
        }
        public void SetAsset(AssetID assetID)
        {
            if (!this.assetValue.Equals(assetID))
            {
                this.assetValue = assetID;
                this.OnHandleValueChanged();
            }
        }
        public void ResetAsset()
        {
            this.SetAsset(AssetID.Empty);
        }

        public void InitBoolean(bool value)
        {
            if(this.boolValue != value)
            {
                this.boolValue = value;
                this.OnHandleInitialized();
            }
        }

        public  void InitInteger(long value)
        {
            if(this.intValue != value)
            {
                this.intValue = value;
                this.OnHandleInitialized();
            }
        }

        public void InitFloat(float value)
        {
            if (this.floatValue != value)
            {
                this.floatValue = value;
                this.OnHandleInitialized();
            }
        }
        public void InitString(string value)
        {
            if (this.stringValue != value)
            {
                this.stringValue = value;
                this.OnHandleInitialized();
            }
        }
        public void SetBoolean(bool value)
        {
            if (this.boolValue != value)
            {
                this.boolValue = value;
                this.OnHandleValueChanged();
            }
        }

        public void SetInteger(long value)
        {
            if (this.intValue != value)
            {
                this.intValue = value;
                this.OnHandleValueChanged();
            }
        }
        public void SetFloat(float value)
        {
            if (this.floatValue != value)
            {
                this.floatValue = value;
                this.OnHandleValueChanged();
            }
        }
        public void SetString(string value)
        {
            if (this.stringValue != value)
            {
                this.stringValue = value;
                this.OnHandleValueChanged();
            }
        }

        public void ClearNoBinds()
        {
            this.UIVariableBindList.RemoveAll((p) => { return p == null; });
        }

        public void Remove(UIVariableBind bind)
        {
            this.UIVariableBindList.Remove(bind);
        }

        public void Add(UIVariableBind bind)
        {
            if(this.UIVariableBindList.IndexOf(bind) == -1)
            {
                this.UIVariableBindList.Add(bind);
            }
        }

        public event Action OnValueChanged
        {
            add
            {
                this.onValueChanged = (Action)Delegate.Combine(this.onValueChanged, value);
            }
            remove
            {
                this.onValueChanged = (Action)Delegate.Remove(this.onValueChanged, value);
            }
        }

        public event Action OnValueInitialized
        {
            add
            {
                this.onValueInitialized = (Action)Delegate.Combine(this.onValueInitialized, value);
            }
            remove
            {
                this.onValueInitialized = (Action)Delegate.Remove(this.onValueInitialized, value);
            }
        }

        public void OnHandleValueChanged()
        {
            if (this.onValueChanged != null) this.onValueChanged();
        }

        public void OnHandleInitialized()
        {
            if (this.onValueInitialized != null) this.onValueInitialized();
        }

    }
}

